New generic I/O ring macros from Andrew Warfield and Tim Deegan.
Currently only used for block-device channels.
40dc4076pVeE1kEEWzcUaNZin65kCA xen/include/public/io/domain_controller.h
41c0c412FLc0gunlJl91qMYscFtXVA xen/include/public/io/ioreq.h
40f5623cTZ80EwjWUBlh44A9F9i_Lg xen/include/public/io/netif.h
+41d40e9b8zCk5VDqhVbuQyhc7G3lqA xen/include/public/io/ring.h
4051db79512nOCGweabrFWO2M2h5ng xen/include/public/physdev.h
40589968wmhPmV5-ENbBYmMjnedgKw xen/include/public/sched_ctl.h
404f3d2eR2Owk-ZcGOx9ULGHg3nrww xen/include/public/trace.h
* If the tap driver is used, we may get pages belonging to either the tap
* or (more likely) the real frontend. The backend must specify which domain
* a given page belongs to in update_va_mapping though. For the moment,
- * we pass in the domid of the real frontend in PROBE messages and store
- * this value in alt_dom. Then on mapping, we try both. This is a Guiness
- * book of records-calibre grim hack, and represents a bit of a security risk.
- * Grant tables will soon solve the problem though!
+ * the tap rewrites the ID field of the request to contain the request index
+ * and the id of the real front end domain.
*/
-static domid_t alt_dom = 0;
+#define BLKTAP_COOKIE 0xbeadfeed
+static inline domid_t ID_TO_DOM(unsigned long id) { return (id >> 16); }
#endif
static int do_block_io_op(blkif_t *blkif, int max_to_do);
static int do_block_io_op(blkif_t *blkif, int max_to_do)
{
- blkif_ring_t *blk_ring = blkif->blk_ring_base;
+ blkif_back_ring_t *blk_ring = &blkif->blk_ring;
blkif_request_t *req;
- BLKIF_RING_IDX i, rp;
+ RING_IDX i, rp;
int more_to_do = 0;
- rp = blk_ring->req_prod;
+ rp = blk_ring->sring->req_prod;
rmb(); /* Ensure we see queued requests up to 'rp'. */
- /* Take items off the comms ring, taking care not to overflow. */
- for ( i = blkif->blk_req_cons;
- (i != rp) && ((i-blkif->blk_resp_prod) != BLKIF_RING_SIZE);
+ for ( i = blk_ring->req_cons;
+ (i != rp) && !RING_REQUEST_CONS_OVERFLOW(BLKIF_RING, blk_ring, i);
i++ )
{
if ( (max_to_do-- == 0) || (NR_PENDING_REQS == MAX_PENDING_REQS) )
break;
}
- req = &blk_ring->ring[MASK_BLKIF_IDX(i)].req;
+ req = RING_GET_REQUEST(BLKIF_RING, blk_ring, i);
switch ( req->operation )
{
case BLKIF_OP_READ:
default:
DPRINTK("error: unknown block io operation [%d]\n",
- blk_ring->ring[i].req.operation);
- make_response(blkif, blk_ring->ring[i].req.id,
- blk_ring->ring[i].req.operation, BLKIF_RSP_ERROR);
+ req->operation);
+ make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
break;
}
}
- blkif->blk_req_cons = i;
+ blk_ring->req_cons = i;
return more_to_do;
}
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
/* Grab the real frontend out of the probe message. */
- alt_dom = (domid_t)req->frame_and_sects[1];
+ if (req->frame_and_sects[1] == BLKTAP_COOKIE)
+ blkif->is_blktap = 1;
#endif
-
+
+
+#ifdef CONFIG_XEN_BLKDEV_TAP_BE
if ( HYPERVISOR_update_va_mapping_otherdomain(
MMAP_VADDR(pending_idx, 0) >> PAGE_SHIFT,
(pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL },
- 0, blkif->domid) ) {
-#ifdef CONFIG_XEN_BLKDEV_TAP_BE
- /* That didn't work. Try alt_dom. */
- if ( HYPERVISOR_update_va_mapping_otherdomain(
- MMAP_VADDR(pending_idx, 0) >> PAGE_SHIFT,
- (pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL },
- 0, alt_dom) )
- goto out;
-#else
+ 0, (blkif->is_blktap ? ID_TO_DOM(req->id) : blkif->domid) ) )
+
+ goto out;
+#else
+ if ( HYPERVISOR_update_va_mapping_otherdomain(
+ MMAP_VADDR(pending_idx, 0) >> PAGE_SHIFT,
+ (pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL },
+ 0, blkif->domid) )
+
goto out;
#endif
- }
rsp = vbd_probe(blkif, (vdisk_t *)MMAP_VADDR(pending_idx, 0),
PAGE_SIZE / sizeof(vdisk_t));
mcl[i].args[1] = (phys_seg[i].buffer & PAGE_MASK) | remap_prot;
mcl[i].args[2] = 0;
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
- mcl[i].args[3] = (alt_dom != 0) ? alt_dom : blkif->domid;
+ mcl[i].args[3] = (blkif->is_blktap) ? ID_TO_DOM(req->id) : blkif->domid;
#else
mcl[i].args[3] = blkif->domid;
#endif
{
blkif_response_t *resp;
unsigned long flags;
+ blkif_back_ring_t *blk_ring = &blkif->blk_ring;
/* Place on the response ring for the relevant domain. */
spin_lock_irqsave(&blkif->blk_ring_lock, flags);
- resp = &blkif->blk_ring_base->
- ring[MASK_BLKIF_IDX(blkif->blk_resp_prod)].resp;
+ resp = RING_GET_RESPONSE(BLKIF_RING, blk_ring, blk_ring->rsp_prod_pvt);
resp->id = id;
resp->operation = op;
resp->status = st;
wmb(); /* Ensure other side can see the response fields. */
- blkif->blk_ring_base->resp_prod = ++blkif->blk_resp_prod;
+ blk_ring->rsp_prod_pvt++;
+ RING_PUSH_RESPONSES(BLKIF_RING, blk_ring);
spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
/* Kick the relevant domain. */
#include <asm-xen/ctrl_if.h>
#include <asm-xen/hypervisor.h>
#include <asm-xen/xen-public/io/blkif.h>
+#include <asm-xen/xen-public/io/ring.h>
#if 0
#define ASSERT(_p) \
typedef struct blkif_st {
/* Unique identifier for this interface. */
- domid_t domid;
- unsigned int handle;
+ domid_t domid;
+ unsigned int handle;
/* Physical parameters of the comms window. */
- unsigned long shmem_frame;
- unsigned int evtchn;
- int irq;
+ unsigned long shmem_frame;
+ unsigned int evtchn;
+ int irq;
/* Comms information. */
- blkif_ring_t *blk_ring_base; /* ioremap()'ed ptr to shmem_frame. */
- BLKIF_RING_IDX blk_req_cons; /* Request consumer. */
- BLKIF_RING_IDX blk_resp_prod; /* Private version of resp. producer. */
+ blkif_back_ring_t blk_ring;
/* VBDs attached to this interface. */
- rb_root_t vbd_rb; /* Mapping from 16-bit vdevices to VBDs. */
- spinlock_t vbd_lock; /* Protects VBD mapping. */
+ rb_root_t vbd_rb; /* Mapping from 16-bit vdevices to VBDs.*/
+ spinlock_t vbd_lock; /* Protects VBD mapping. */
/* Private fields. */
enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
/*
* We therefore need to store the id from the original request.
*/
u8 disconnect_rspid;
+#ifdef CONFIG_XEN_BLKDEV_TAP_BE
+ /* Is this a blktap frontend */
+ unsigned int is_blktap;
+#endif
struct blkif_st *hash_next;
struct list_head blkdev_list;
spinlock_t blk_ring_lock;
* must still be notified to the remote driver.
*/
unbind_evtchn_from_irq(blkif->evtchn);
- vfree(blkif->blk_ring_base);
+ vfree(blkif->blk_ring.sring);
/* Construct the deferred response message. */
cmsg.type = CMSG_BLKIF_BE;
void blkif_connect(blkif_be_connect_t *connect)
{
- domid_t domid = connect->domid;
- unsigned int handle = connect->blkif_handle;
- unsigned int evtchn = connect->evtchn;
- unsigned long shmem_frame = connect->shmem_frame;
+ domid_t domid = connect->domid;
+ unsigned int handle = connect->blkif_handle;
+ unsigned int evtchn = connect->evtchn;
+ unsigned long shmem_frame = connect->shmem_frame;
struct vm_struct *vma;
- pgprot_t prot;
- int error;
- blkif_t *blkif;
+ pgprot_t prot;
+ int error;
+ blkif_t *blkif;
+ blkif_sring_t *sring;
blkif = blkif_find_by_handle(domid, handle);
if ( unlikely(blkif == NULL) )
vfree(vma->addr);
return;
}
-
+ sring = (blkif_sring_t *)vma->addr;
+ SHARED_RING_INIT(BLKIF_RING, sring);
+ BACK_RING_INIT(BLKIF_RING, &blkif->blk_ring, sring);
+
blkif->evtchn = evtchn;
blkif->irq = bind_evtchn_to_irq(evtchn);
blkif->shmem_frame = shmem_frame;
- blkif->blk_ring_base = (blkif_ring_t *)vma->addr;
blkif->status = CONNECTED;
blkif_get(blkif);
* Copyright (c) 2003-2004, Keir Fraser & Steve Hand
* Modifications by Mark A. Williamson are (c) Intel Research Cambridge
* Copyright (c) 2004, Christian Limpach
+ * Copyright (c) 2004, Andrew Warfield
*
* This file may be distributed separately from the Linux kernel, or
* incorporated into other software packages, subject to the following license:
static int blkif_control_rsp_valid;
static blkif_response_t blkif_control_rsp;
-static blkif_ring_t *blk_ring = NULL;
-static BLKIF_RING_IDX resp_cons; /* Response consumer for comms ring. */
-static BLKIF_RING_IDX req_prod; /* Private request producer. */
+static blkif_front_ring_t blk_ring;
unsigned long rec_ring_free;
-blkif_request_t rec_ring[BLKIF_RING_SIZE];
+blkif_request_t rec_ring[RING_SIZE(BLKIF_RING, &blk_ring)];
static int recovery = 0; /* "Recovery in progress" flag. Protected
* by the blkif_io_lock */
-/* We plug the I/O ring if the driver is suspended or if the ring is full. */
-#define BLKIF_RING_FULL (((req_prod - resp_cons) == BLKIF_RING_SIZE) || \
- (blkif_state != BLKIF_STATE_CONNECTED))
-
static void kick_pending_request_queues(void);
int __init xlblk_init(void);
{
unsigned long free = rec_ring_free;
- if ( free > BLKIF_RING_SIZE )
+ if ( free > RING_SIZE(BLKIF_RING, &blk_ring) )
BUG();
rec_ring_free = rec_ring[free].id;
static inline void flush_requests(void)
{
DISABLE_SCATTERGATHER();
- wmb(); /* Ensure that the frontend can see the requests. */
- blk_ring->req_prod = req_prod;
+ RING_PUSH_REQUESTS(BLKIF_RING, &blk_ring);
notify_via_evtchn(blkif_evtchn);
}
return 1;
/* Fill out a communications ring structure. */
- ring_req = &blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req;
+ ring_req = RING_GET_REQUEST(BLKIF_RING, &blk_ring, blk_ring.req_prod_pvt);
id = GET_ID_FROM_FREELIST();
rec_ring[id].id = (unsigned long) req;
}
}
- req_prod++;
-
+ blk_ring.req_prod_pvt++;
+
/* Keep a private copy so we can reissue requests when recovering. */
translate_req_to_pfn( &rec_ring[id], ring_req);
continue;
}
- if ( BLKIF_RING_FULL )
+ if ( RING_FULL(BLKIF_RING, &blk_ring) )
{
blk_stop_queue(rq);
break;
{
struct request *req;
blkif_response_t *bret;
- BLKIF_RING_IDX i, rp;
+ RING_IDX i, rp;
unsigned long flags;
-
+
spin_lock_irqsave(&blkif_io_lock, flags);
if ( unlikely(blkif_state == BLKIF_STATE_CLOSED) ||
spin_unlock_irqrestore(&blkif_io_lock, flags);
return IRQ_HANDLED;
}
-
- rp = blk_ring->resp_prod;
+
+ rp = blk_ring.sring->rsp_prod;
rmb(); /* Ensure we see queued responses up to 'rp'. */
- for ( i = resp_cons; i != rp; i++ )
+ for ( i = blk_ring.rsp_cons; i != rp; i++ )
{
unsigned long id;
- bret = &blk_ring->ring[MASK_BLKIF_IDX(i)].resp;
+ bret = RING_GET_RESPONSE(BLKIF_RING, &blk_ring, i);
id = bret->id;
req = (struct request *)rec_ring[id].id;
-
blkif_completion( &rec_ring[id] );
ADD_ID_TO_FREELIST(id); /* overwrites req */
BUG();
}
}
-
- resp_cons = i;
+ blk_ring.rsp_cons = i;
+
kick_pending_request_queues();
spin_unlock_irqrestore(&blkif_io_lock, flags);
{
/* We kick pending request queues if the ring is reasonably empty. */
if ( (nr_pending != 0) &&
- ((req_prod - resp_cons) < (BLKIF_RING_SIZE >> 1)) )
+ (RING_PENDING_REQUESTS(BLKIF_RING, &blk_ring) <
+ (RING_SIZE(&blk_ring) >> 1)) )
{
/* Attempt to drain the queue, but bail if the ring becomes full. */
- while ( (nr_pending != 0) && !BLKIF_RING_FULL )
+ while ( (nr_pending != 0) && !RING_FULL(BLKIF_RING, &blk_ring) )
do_blkif_request(pending_queues[--nr_pending]);
}
}
(sg_dev == device) &&
(sg_next_sect == sector_number) )
{
-
- req = &blk_ring->ring[MASK_BLKIF_IDX(req_prod-1)].req;
+ req = RING_GET_REQUEST(BLKIF_RING, &blk_ring,
+ blk_ring.rsp_prod_pvt - 1);
bh = (struct buffer_head *)id;
bh->b_reqnext = (struct buffer_head *)rec_ring[req->id].id;
return 0;
}
- else if ( BLKIF_RING_FULL )
+ else if ( RING_FULL(BLKIF_RING, &blk_ring) )
{
return 1;
}
}
/* Fill out a communications ring structure. */
- req = &blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req;
+ req = RING_GET_REQUEST(BLKIF_RING, &blk_ring, blk_ring.req_prod_pvt);
xid = GET_ID_FROM_FREELIST();
rec_ring[xid].id = id;
req->nr_segments = 1;
req->frame_and_sects[0] = buffer_ma | (fsect<<3) | lsect;
- req_prod++;
-
/* Keep a private copy so we can reissue requests when recovering. */
translate_req_to_pfn(&rec_ring[xid], req );
+ blk_ring.req_prod_pvt++;
+
return 0;
}
static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
{
- BLKIF_RING_IDX i, rp;
+ RING_IDX i, rp;
unsigned long flags;
struct buffer_head *bh, *next_bh;
return;
}
- rp = blk_ring->resp_prod;
+ rp = blk_ring.rsp_prod;
rmb(); /* Ensure we see queued responses up to 'rp'. */
- for ( i = resp_cons; i != rp; i++ )
+ for ( i = blk_ring.rsp_cons; i != rp; i++ )
{
unsigned long id;
- blkif_response_t *bret = &blk_ring->ring[MASK_BLKIF_IDX(i)].resp;
-
+ blkif_response_t *bret;
+
+ bret = RING_GET_RESPONSE(BLKIF_RING, &blkif_ring, i);
id = bret->id;
bh = (struct buffer_head *)rec_ring[id].id;
default:
BUG();
}
- }
-
- resp_cons = i;
+ blk_ring.rsp_cons = i;
+
kick_pending_request_queues();
spin_unlock_irqrestore(&io_request_lock, flags);
void blkif_control_send(blkif_request_t *req, blkif_response_t *rsp)
{
unsigned long flags, id;
+ blkif_request_t *req_d;
retry:
- while ( (req_prod - resp_cons) == BLKIF_RING_SIZE )
+ while ( RING_FULL(BLKIF_RING, &blk_ring) )
{
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
}
spin_lock_irqsave(&blkif_io_lock, flags);
- if ( (req_prod - resp_cons) == BLKIF_RING_SIZE )
+ if ( RING_FULL(BLKIF_RING, &blk_ring) )
{
spin_unlock_irqrestore(&blkif_io_lock, flags);
goto retry;
}
DISABLE_SCATTERGATHER();
- blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req = *req;
+ req_d = RING_GET_REQUEST(BLKIF_RING, &blk_ring, blk_ring.req_prod_pvt);
+ *req_d = *req;
id = GET_ID_FROM_FREELIST();
- blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req.id = id;
+ req_d->id = id;
rec_ring[id].id = (unsigned long) req;
translate_req_to_pfn( &rec_ring[id], req );
- req_prod++;
+ blk_ring.req_prod_pvt++;
flush_requests();
spin_unlock_irqrestore(&blkif_io_lock, flags);
blkif_fe_interface_connect_t *msg = (void*)cmsg.msg;
msg->handle = 0;
- msg->shmem_frame = (virt_to_machine(blk_ring) >> PAGE_SHIFT);
+ msg->shmem_frame = (virt_to_machine(blk_ring.sring) >> PAGE_SHIFT);
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
}
spin_unlock_irq(&blkif_io_lock);
/* Free resources associated with old device channel. */
- if ( blk_ring != NULL )
+ if ( blk_ring.sring != NULL )
{
- free_page((unsigned long)blk_ring);
- blk_ring = NULL;
+ free_page((unsigned long)blk_ring.sring);
+ blk_ring.sring = NULL;
}
free_irq(blkif_irq, NULL);
blkif_irq = 0;
/* Move from CLOSED to DISCONNECTED state. */
static void blkif_disconnect(void)
{
- if ( blk_ring != NULL )
- free_page((unsigned long)blk_ring);
- blk_ring = (blkif_ring_t *)__get_free_page(GFP_KERNEL);
- blk_ring->req_prod = blk_ring->resp_prod = resp_cons = req_prod = 0;
+ blkif_sring_t *sring;
+
+ if ( blk_ring.sring != NULL )
+ free_page((unsigned long)blk_ring.sring);
+
+ sring = (blkif_sring_t *)__get_free_page(GFP_KERNEL);
+ SHARED_RING_INIT(BLKIF_RING, sring);
+ FRONT_RING_INIT(BLKIF_RING, &blk_ring, sring);
blkif_state = BLKIF_STATE_DISCONNECTED;
blkif_send_interface_connect();
}
static void blkif_recover(void)
{
int i;
+ blkif_request_t *req;
/* Hmm, requests might be re-ordered when we re-issue them.
* This will need to be fixed once we have barriers */
/* Stage 1 : Find active and move to safety. */
- for ( i = 0; i < BLKIF_RING_SIZE; i++ )
+ for ( i = 0; i < RING_SIZE(BLKIF_RING, &blk_ring); i++ )
{
if ( rec_ring[i].id >= PAGE_OFFSET )
{
- translate_req_to_mfn(
- &blk_ring->ring[req_prod].req, &rec_ring[i]);
- req_prod++;
+ req = RING_GET_REQUEST(BLKIF_RING, &blk_ring,
+ blk_ring.req_prod_pvt);
+ translate_req_to_mfn(req, &rec_ring[i]);
+ blk_ring.req_prod_pvt++;
}
}
/* Stage 2 : Set up shadow list. */
- for ( i = 0; i < req_prod; i++ )
+ for ( i = 0; i < blk_ring.req_prod_pvt; i++ )
{
- rec_ring[i].id = blk_ring->ring[i].req.id;
- blk_ring->ring[i].req.id = i;
- translate_req_to_pfn(&rec_ring[i], &blk_ring->ring[i].req);
+ req = RING_GET_REQUEST(BLKIF_RING, &blk_ring, i);
+ rec_ring[i].id = req->id;
+ req->id = i;
+ translate_req_to_pfn(&rec_ring[i], req);
}
/* Stage 3 : Set up free list. */
- for ( ; i < BLKIF_RING_SIZE; i++ )
+ for ( ; i < RING_SIZE(BLKIF_RING, &blk_ring); i++ )
rec_ring[i].id = i+1;
- rec_ring_free = req_prod;
- rec_ring[BLKIF_RING_SIZE-1].id = 0x0fffffff;
+ rec_ring_free = blk_ring.req_prod_pvt;
+ rec_ring[RING_SIZE(BLKIF_RING, &blk_ring)-1].id = 0x0fffffff;
/* blk_ring->req_prod will be set when we flush_requests().*/
wmb();
printk(KERN_INFO "xen_blk: Initialising virtual block device driver\n");
rec_ring_free = 0;
- for ( i = 0; i < BLKIF_RING_SIZE; i++ )
+ for ( i = 0; i < RING_SIZE(BLKIF_RING, &blk_ring); i++ )
rec_ring[i].id = i+1;
- rec_ring[BLKIF_RING_SIZE-1].id = 0x0fffffff;
+ rec_ring[RING_SIZE(BLKIF_RING, &blk_ring)-1].id = 0x0fffffff;
(void)ctrl_if_register_receiver(CMSG_BLKIF_FE, blkif_ctrlif_rx,
CALLBACK_IN_BLOCKING_CONTEXT);
#include <linux/devfs_fs_kernel.h>
#include <asm-xen/xen-public/xen.h>
#include <asm-xen/xen-public/io/blkif.h>
+#include <asm-xen/xen-public/io/ring.h>
#include <asm/io.h>
#include <asm/atomic.h>
#include <asm/uaccess.h>
#ifndef __XEN_PUBLIC_IO_BLKIF_H__
#define __XEN_PUBLIC_IO_BLKIF_H__
+#include <asm-xen/xen-public/io/ring.h>
+
#define blkif_vdev_t u16
#define blkif_sector_t u64
#define BLKIF_RSP_OKAY 0 /* non-specific 'okay' */
/*
- * We use a special capitalised type name because it is _essential_ that all
- * arithmetic on indexes is done on an integer type of the correct size.
- */
-typedef u32 BLKIF_RING_IDX;
-
-/*
- * Ring indexes are 'free running'. That is, they are not stored modulo the
- * size of the ring buffer. The following macro converts a free-running counter
- * into a value that can directly index a ring-buffer array.
+ * Generate blkif ring structures and types.
*/
-#define MASK_BLKIF_IDX(_i) ((_i)&(BLKIF_RING_SIZE-1))
-
-typedef struct {
- BLKIF_RING_IDX req_prod; /* 0: Request producer. Updated by front-end. */
- BLKIF_RING_IDX resp_prod; /* 4: Response producer. Updated by back-end. */
- union { /* 8 */
- blkif_request_t req;
- blkif_response_t resp;
- } PACKED ring[BLKIF_RING_SIZE];
-} PACKED blkif_ring_t;
+#define BLKIF_RING RING_PARAMS(blkif_request_t, blkif_response_t, PAGE_SIZE)
+DEFINE_RING_TYPES(blkif, BLKIF_RING);
/*
* BLKIF_OP_PROBE:
--- /dev/null
+/*
+ * Shared producer-consumer ring macros.
+ * Tim Deegan and Andrew Warfield November 2004.
+ */
+
+#ifndef __XEN_PUBLIC_IO_RING_H__
+#define __XEN_PUBLIC_IO_RING_H__
+
+typedef unsigned int RING_IDX;
+
+/* This is horrible: it rounds a 32-bit unsigned constant down to the
+ * nearest power of two, by finding the highest set bit. */
+#define __RD2PO2(_x) (((_x) & 0x80000000) ? 0x80000000 : \
+ ((_x) & 0x40000000) ? 0x40000000 : \
+ ((_x) & 0x20000000) ? 0x20000000 : \
+ ((_x) & 0x10000000) ? 0x10000000 : \
+ ((_x) & 0x08000000) ? 0x08000000 : \
+ ((_x) & 0x04000000) ? 0x04000000 : \
+ ((_x) & 0x02000000) ? 0x02000000 : \
+ ((_x) & 0x01000000) ? 0x01000000 : \
+ ((_x) & 0x00800000) ? 0x00800000 : \
+ ((_x) & 0x00400000) ? 0x00400000 : \
+ ((_x) & 0x00200000) ? 0x00200000 : \
+ ((_x) & 0x00100000) ? 0x00100000 : \
+ ((_x) & 0x00080000) ? 0x00080000 : \
+ ((_x) & 0x00040000) ? 0x00040000 : \
+ ((_x) & 0x00020000) ? 0x00020000 : \
+ ((_x) & 0x00010000) ? 0x00010000 : \
+ ((_x) & 0x00008000) ? 0x00008000 : \
+ ((_x) & 0x00004000) ? 0x00004000 : \
+ ((_x) & 0x00002000) ? 0x00002000 : \
+ ((_x) & 0x00001000) ? 0x00001000 : \
+ ((_x) & 0x00000800) ? 0x00000800 : \
+ ((_x) & 0x00000400) ? 0x00000400 : \
+ ((_x) & 0x00000200) ? 0x00000200 : \
+ ((_x) & 0x00000100) ? 0x00000100 : \
+ ((_x) & 0x00000080) ? 0x00000080 : \
+ ((_x) & 0x00000040) ? 0x00000040 : \
+ ((_x) & 0x00000020) ? 0x00000020 : \
+ ((_x) & 0x00000010) ? 0x00000010 : \
+ ((_x) & 0x00000008) ? 0x00000008 : \
+ ((_x) & 0x00000004) ? 0x00000004 : \
+ ((_x) & 0x00000002) ? 0x00000002 : \
+ ((_x) & 0x00000001) ? 0x00000001 : 0x00000000)
+
+/* Given a shared ring, tell me how many entries there are in it. The
+ * rule is: a ring contains as many entries as will fit, rounded down to
+ * the nearest power of two (so we can mask with (size-1) to loop
+ * around) */
+#define __SRING_SIZE(__params, __esize) \
+ __RD2PO2((sizeof((__params)->size) - (2 * sizeof(RING_IDX))) / (__esize))
+#define SRING_SIZE(__params, __sringp) \
+ __SRING_SIZE(__params, sizeof (__sringp)->ring[0])
+
+/*
+ * Macros to make the correct C datatypes for a new kind of ring.
+ *
+ * To make a new ring datatype, you need to have two message structures,
+ * let's say request_t, and response_t already defined. You also need to
+ * know how big the shared memory region you want the ring to occupy is
+ * (PAGE_SIZE, of instance).
+ *
+ * In a header where you want the ring datatype declared, you then do:
+ *
+ * #define MY_RING RING_PARAMS(request_t, response_t, PAGE_SIZE)
+ * DEFINE_RING_TYPES(mytag, MY_RING);
+ *
+ * These expand out to give you a set of types, as you can see below.
+ * The most important of these are:
+ *
+ * mytag_sring_t - The shared ring.
+ * mytag_front_ring_t - The 'front' half of the ring.
+ * mytag_back_ring_t - The 'back' half of the ring.
+ *
+ * Use the RING_PARAMS define (MY_RING above) as a first parameter on all
+ * the ring functions. To initialize a ring in your code, on the front
+ * half, you do a:
+ *
+ * mytag_front_ring_t front_ring;
+ *
+ * SHARED_RING_INIT(MY_RING, (mytag_sring_t *)shared_page)
+ * FRONT_RING_INIT(MY_RING, &front_ring, (mytag_sring_t *)shared_page)
+ *
+ * Initializing the back follows similarly...
+ */
+
+/* NB: RING SIZING. (a note to ease future debugging...)
+ *
+ * Passing size information into the ring macros is made difficult by
+ * the lack of a reasonable constant declaration in C. To get around this,
+ * the RING_PARAMS define places the requested size of the ring as the
+ * static size of the 'size' array in the anonymous RING_PARAMS struct.
+ * While this struct is never actually instantiated, __SRING_SIZE is
+ * able to use sizeof() to get at the constant size.
+ */
+
+#define RING_PARAMS(__req_t, __rsp_t, __size) \
+((struct { \
+ char size[__size]; \
+ __req_t req; \
+ __rsp_t rsp; \
+ \
+} *) 0)
+
+
+#define DEFINE_RING_TYPES(__name, __params) \
+ \
+/* Shared ring entry */ \
+union __name##_sring_entry { \
+ typeof ((__params)->req) req; \
+ typeof ((__params)->rsp) rsp; \
+} PACKED; \
+ \
+/* Shared ring page */ \
+struct __name##_sring { \
+ RING_IDX req_prod; \
+ RING_IDX rsp_prod; \
+ union __name##_sring_entry \
+ ring[__SRING_SIZE(__params, sizeof (union __name##_sring_entry))]; \
+} PACKED; \
+ \
+/* "Front" end's private variables */ \
+struct __name##_front_ring { \
+ RING_IDX req_prod_pvt; \
+ RING_IDX rsp_cons; \
+ struct __name##_sring *sring; \
+}; \
+ \
+/* "Back" end's private variables */ \
+struct __name##_back_ring { \
+ RING_IDX rsp_prod_pvt; \
+ RING_IDX req_cons; \
+ struct __name##_sring *sring; \
+}; \
+ \
+/* Syntactic sugar */ \
+typedef struct __name##_sring __name##_sring_t; \
+typedef struct __name##_front_ring __name##_front_ring_t; \
+typedef struct __name##_back_ring __name##_back_ring_t;
+
+/*
+ * Macros for manipulating rings.
+ *
+ * FRONT_RING_whatever works on the "front end" of a ring: here
+ * requests are pushed on to the ring and responses taken off it.
+ *
+ * BACK_RING_whatever works on the "back end" of a ring: here
+ * requests are taken off the ring and responses put on.
+ *
+ * N.B. these macros do NO INTERLOCKS OR FLOW CONTROL.
+ * This is OK in 1-for-1 request-response situations where the
+ * requestor (front end) never has more than SRING_SIZE()-1
+ * outstanding requests.
+ */
+
+
+/* Initialising empty rings */
+#define SHARED_RING_INIT(_p, _s) do { \
+ (_s)->req_prod = 0; \
+ (_s)->rsp_prod = 0; \
+} while(0)
+
+#define FRONT_RING_INIT(_p, _r, _s) do { \
+ (_r)->req_prod_pvt = 0; \
+ (_r)->rsp_cons = 0; \
+ (_r)->sring = (_s); \
+} while (0)
+
+#define BACK_RING_INIT(_p, _r, _s) do { \
+ (_r)->rsp_prod_pvt = 0; \
+ (_r)->req_cons = 0; \
+ (_r)->sring = (_s); \
+} while (0)
+
+/* Initialize to existing shared indexes -- for recovery */
+#define FRONT_RING_ATTACH(_p, _r, _s) do { \
+ (_r)->sring = (_s); \
+ (_r)->req_prod_pvt = (_s)->req_prod; \
+ (_r)->rsp_cons = (_s)->rsp_prod; \
+} while (0)
+
+#define BACK_RING_ATTACH(_p, _r, _s) do { \
+ (_r)->sring = (_s); \
+ (_r)->rsp_prod_pvt = (_s)->rsp_prod; \
+ (_r)->req_cons = (_s)->req_prod; \
+} while (0)
+
+
+/* How to mask off a number for use as an offset into a ring
+ * N.B. This evalutes its second argument once but its first often */
+#define __SHARED_RING_MASK(_p, _s, _i) \
+ ((_i) & (SRING_SIZE((_p), (_s)) - 1))
+
+/* How big is this ring? */
+#define RING_SIZE(_p, _r) SRING_SIZE((_p), (_r)->sring)
+
+/* How many empty slots are on a ring? */
+#define RING_PENDING_REQUESTS(_p, _r) \
+ ( ((_r)->req_prod_pvt - (_r)->rsp_cons) )
+
+/* Test if there is an empty slot available on the front ring.
+ * (This is only meaningful from the front. )
+ */
+#define RING_FULL(_p, _r) \
+ (((_r)->req_prod_pvt - (_r)->rsp_cons) == SRING_SIZE((_p), (_r)->sring))
+
+/* Test if there are outstanding messages to be processed on a ring. */
+#define RING_HAS_UNCONSUMED_RESPONSES(_p, _r) \
+ ( (_r)->rsp_cons != (_r)->sring->rsp_prod )
+
+#define RING_HAS_UNCONSUMED_REQUESTS(_p, _r) \
+ ( ((_r)->req_cons != (_r)->sring->req_prod ) && \
+ (((_r)->req_cons - (_r)->rsp_prod_pvt) != \
+ SRING_SIZE((_p), (_r)->sring)) )
+
+/* Test if there are messages waiting to be pushed. */
+#define RING_HAS_UNPUSHED_REQUESTS(_p, _r) \
+ ( (_r)->req_prod_pvt != (_r)->sring->req_prod )
+
+#define RING_HAS_UNPUSHED_RESPONSES(_p, _r) \
+ ( (_r)->rsp_prod_pvt != (_r)->sring->rsp_prod )
+
+
+/* Copy the private producer pointer into the shared ring so the other end
+ * can see the updates we've made. */
+#define RING_PUSH_REQUESTS(_p, _r) do { \
+ wmb(); \
+ (_r)->sring->req_prod = (_r)->req_prod_pvt; \
+} while (0)
+
+#define RING_PUSH_RESPONSES(_p, _r) do { \
+ wmb(); \
+ (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt; \
+} while (0)
+
+/* Direct access to individual ring elements, by index.
+ */
+#define RING_GET_REQUEST(_p, _r, _idx) \
+ (&((_r)->sring->ring[ \
+ __SHARED_RING_MASK((_p), (_r)->sring, (_idx)) \
+ ].req))
+
+#define RING_GET_RESPONSE(_p, _r, _idx) \
+ (&((_r)->sring->ring[ \
+ __SHARED_RING_MASK((_p), (_r)->sring, (_idx)) \
+ ].rsp))
+
+/* Loop termination condition: Would the specified index overflow the
+ * ring?
+ */
+#define RING_REQUEST_CONS_OVERFLOW(_p, _r, _cons) \
+ (((_cons) - (_r)->rsp_prod_pvt) >= SRING_SIZE((_p), (_r)->sring))
+
+#endif /* __XEN_PUBLIC_IO_RING_H__ */